package cn.com.cis.plugins.shiro;

import java.util.List;

import javax.annotation.PostConstruct;

import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;

import cn.com.cis.domain.Role;
import cn.com.cis.domain.User;
import cn.com.cis.service.RoleService;
import cn.com.cis.service.UserService;
import cn.com.cis.utils.security.CustomCredentialsMatcher;
import cn.com.cis.utils.security.PasswordHash;

public class ShiroJdbcRealmWithPh extends AuthorizingRealm {

    private UserService userService;
    private RoleService roleService;
    
    // 登陆验证调用
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authcToken) throws AuthenticationException {
    	
    	UsernamePasswordToken userToken = (UsernamePasswordToken) authcToken;
    	String username = userToken.getUsername();

    	User user = userService.selectUserByUsername(username);
    	if(null == user){
    		throw new AuthenticationException("用户名或者密码不正确！");
    	}
    	
    	String saltHash = PasswordHash.PBKDF2_ITERATIONS + ":" + user.getSalt() + ":" + user.getPassword();
    	SimpleAuthenticationInfo simpleAuth = new SimpleAuthenticationInfo(user, saltHash, "Shiro JDBC Realm");
        return simpleAuth;
    }
    
	@Override
	public boolean supports(AuthenticationToken token) {
		// 仅支持 UsernamePasswordToken 类型的 Token
		return token instanceof UsernamePasswordToken;
	}

	// 资源访问，权限审查调用
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
    	
    	SimpleAuthorizationInfo authInfo = new SimpleAuthorizationInfo();
    	
    	User loginUser = (User)principals.getPrimaryPrincipal();
    	
    	// add roles current login user hold, and the permission these roles have
    	List<Role> holdRoles = userService.selectUserRoles(loginUser.getId());
    	for(Role role : holdRoles){
    		authInfo.addRole(role.getRoleName());
    		
    		for(String rolePermission : roleService.selectPermissionsForRole(role.getRoleId())){
    			authInfo.addStringPermission(rolePermission);
    		}
    	}
    	
    	// additional permissions for current user
    	for(String userPermission : userService.selectPermissionsForUser(loginUser.getId())){
    		authInfo.addStringPermission(userPermission);
    	}
    	
    	return authInfo;
    }

    public AuthorizationInfo getAuthorizationInfo(PrincipalCollection principals) {
        return super.getAuthorizationInfo(principals);
    }

    @PostConstruct
    public void initCredentialsMatcher() {
    	// 为何使用自定义密码检验类
    	// refer to: 
    	//   http://blog.jobbole.com/61872/
    	//   https://crackstation.net/hashing-security.htm
        setCredentialsMatcher(new CustomCredentialsMatcher()); 
    }

    public void setUserService(UserService userService) {
        this.userService = userService;
    }
    
    public void setRoleService(RoleService roleService) {
        this.roleService = roleService;
    }
}
